package cool.taomu.toolkit

import com.google.inject.multibindings.MapBinder
import cool.taomu.toolkit.crypto.Base64
import cool.taomu.toolkit.crypto.ICrypto
import cool.taomu.toolkit.utils.NetworkInterfacesUtils
import java.io.InputStream
import java.util.Collection
import java.util.HashMap
import java.util.List
import java.util.Map
import javax.sql.DataSource
import org.apache.commons.lang3.exception.ExceptionUtils
import org.apache.commons.vfs2.FileObject
import org.apache.commons.vfs2.FileSystemException
import org.apache.commons.vfs2.FileSystemManager
import org.apache.commons.vfs2.VFS
import org.eclipse.xtend.lib.annotations.Accessors
import org.slf4j.LoggerFactory

@Accessors
class TaomuConfigure {
    val static LOG = LoggerFactory.getLogger(TaomuConfigure);

    YamlUtils yamlUtils
    FileSystemManager vfs = VFS.manager;
    Map<String, Collection<Object>> configure ;
    MapBinder<String, DataSource> mapBinder;

    new() {
        this(new Base64())
    }

    new(ICrypto crypto) {
        this.yamlUtils = new YamlUtils(crypto)
    }

    static interface BinderFunction {
        def void apply(Object arg)
    }

    def boolean isExist(String name) {
        return this.configure.containsKey(name)
    }

    def boolean binder(String name, BinderFunction func) {
        LOG.info("binder:{}", this.configure)
        if (!this.configure.containsKey(name)) {
            return false;
        }
        var cs = this.configure.get(name)
        LOG.debug("Key:{},value:{}", name, cs)
        cs.forEach [
            if (it instanceof List) {
                it.forEach [
                    func.apply(it)
                ]
            }
        ]
        return true;
    }

    def loadConfig() {
        try(var ymlfileObject = vfs.resolveFile("res://appliction.yml")) {
            if (ymlfileObject.exists && !ymlfileObject.content.empty) {
                configure = loadSubConfig(ymlfileObject, vfs, "yml")
            } else {
                configure = #{}
            }
        } catch (FileSystemException fsex) {
            try(var ymlfileObject = vfs.resolveFile("res://config/appliction.yml")) {
                if (ymlfileObject.exists && !ymlfileObject.content.empty) {
                    configure = loadSubConfig(ymlfileObject, vfs, "yml")
                } else {
                    configure = #{}
                }
            } catch (FileSystemException fsex3) {
                var path = System.getProperty("user.dir");
                var ymlPath = String.format("file://%s/config/application.yml", path)
                try(var ymlfileObject = vfs.resolveFile(ymlPath)) {
                    if (ymlfileObject.exists && !ymlfileObject.content.empty) {
                        configure = loadSubConfig(ymlfileObject, vfs, "yml")
                    } else {
                        configure = #{}
                    }
                } catch (FileSystemException fsex5) {
                    LOG.info("缺少配置文件appliction.yml\n{}", ExceptionUtils.getStackTrace(fsex5));
                    configure = loadNetworkConfig(vfs)
                }
            }
        }
        this
    }

    protected def loadNetworkConfig(FileSystemManager vfs) {
        LOG.info("尝试加载application-host.yml配置文件")
        var networkInfo = NetworkInterfacesUtils.networkInterfacesInfo
        val map = new HashMap();
        networkInfo.findFirst [
            val path = String.format("res://application-%s.yml", it.ipv4)
            try(var ymlActivefileObject = vfs.resolveFile(path)) {
                if (ymlActivefileObject.exists) {
                    LOG.info("找到网络 {}，对应的配置文件", it)
                    map.putAll(configBinder(ymlActivefileObject.content.inputStream));
                    return true;
                }
            } catch (FileSystemException fsex) {
                val path3 = String.format("res://config/application-%s.yml", it.ipv4)
                try(var ymlActivefileObject = vfs.resolveFile(path3)) {
                    if (ymlActivefileObject.exists) {
                        LOG.info("找到网络 {}，对应的配置文件", it)
                        map.putAll(configBinder(ymlActivefileObject.content.inputStream));
                        return true;
                    }
                } catch (FileSystemException fsex3) {
                    var pathDir = System.getProperty("user.dir");
                    var path5 = String.format("file://%s/config/application-%s.yml", pathDir, it.ipv4)
                    try(var ymlActivefileObject = vfs.resolveFile(path5)) {
                        if (ymlActivefileObject.exists) {
                            LOG.info("找到网络 {}，对应的配置文件", it)
                            map.putAll(configBinder(ymlActivefileObject.content.inputStream));
                            return true;
                        }
                    } catch (FileSystemException fsex5) {
                        LOG.info("缺少配置文件appliction-{}.yml\n{}", it.ipv4, ExceptionUtils.getStackTrace(fsex5));
                    }
                }
            }
            return false;
        ]
        return map;
    }

    private def loadSubConfig(FileObject ymlfileObject, FileSystemManager vfs, String type) {

        var nwInfo = this.loadNetworkConfig(vfs)
        if (nwInfo.size > 0) {
            return nwInfo;
        }
        var String profile = System.getProperty("taomu.profiles.active");
        if (!profile.nullOrEmpty) {
            LOG.info("从命令行获取的taomu.profiles.active值：{}", profile)
            var active = profile
            return loadConfigure(active, vfs)
        } else if (type.equals("yml") && ymlfileObject !== null) {
            var pro = yamlUtils.toProperties(ymlfileObject.content.inputStream, null)
            if (pro.containsKey("taomu.profiles.active")) {
                var active = pro.get("taomu.profiles.active")
                LOG.info("从配置文件获取的taomu.profiles.active值：{}", active)
                return loadConfigure(active, vfs)
            }
        }
    }

    private def loadConfigure(Object active, FileSystemManager vfs) {
        val path = String.format("res://application-%s.yml", active)
        try(var ymlActivefileObject = vfs.resolveFile(path)) {
            if (ymlActivefileObject.exists) {
                LOG.info("读取jar包内的文件：{}", path);
                return configBinder(ymlActivefileObject.content.inputStream);
            }
        } catch (FileSystemException fsex) {
            val path3 = String.format("res://config/application-%s.yml", active)
            try(var ymlActivefileObject = vfs.resolveFile(path3)) {
                if (ymlActivefileObject.exists) {
                    LOG.info("读取jar包外的文件：{}", path3);
                    return configBinder(ymlActivefileObject.content.inputStream);
                }
            } catch (FileSystemException fsex3) {
                var pathDir = System.getProperty("user.dir");
                var path5 = String.format("file://%s/config/application-%s.yml", pathDir, active)
                try(var ymlActivefileObject = vfs.resolveFile(path5)) {
                    if (ymlActivefileObject.exists) {
                        LOG.info("读取jar包外的文件：{}", path5);
                        return configBinder(ymlActivefileObject.content.inputStream);
                    }
                } catch (FileSystemException fsex5) {
                    LOG.info("缺少配置文件appliction-{}.yml\n{}", active, ExceptionUtils.getStackTrace(fsex5));
                    System.exit(1);
                }
            }
        }
    }

    private def configBinder(InputStream inputStream) {
        return this.yamlUtils.toPropertiesMap(inputStream);
    }
}
